Bidirectional Sync¶
This demo mirrors https://niivue.com/demos/features/sync.bidirectional.html.
In [1]:
from pathlib import Path
from ipyniivue import download_dataset
BASE_API_URL = "https://niivue.com/demos/images/"
DATA_FOLDER = Path("images")
# Download data for example
download_dataset(
BASE_API_URL,
DATA_FOLDER,
files=[
"pcasl.nii.gz",
"aal.nii.gz",
"mni152.nii.gz",
],
)
pcasl.nii.gz already exists. aal.nii.gz already exists. mni152.nii.gz already exists. Dataset downloaded successfully to images.
In [2]:
import ipywidgets as widgets
from IPython.display import display
from ipyniivue import MultiplanarType, NiiVue
## Create Three NiiVue Instances
nv1 = NiiVue(
height=400,
multiplanar_force_render=True,
back_color=(0.0, 0.0, 0.0, 1.0),
)
nv2 = NiiVue(
height=400,
multiplanar_force_render=True,
back_color=(0.0, 0.0, 0.0, 1.0),
)
nv3 = NiiVue(
height=400,
multiplanar_force_render=True,
back_color=(0.0, 0.0, 0.0, 1.0),
)
## Load Volumes
nv1.load_volumes([{"path": DATA_FOLDER / "pcasl.nii.gz"}])
nv2.load_volumes([{"path": DATA_FOLDER / "aal.nii.gz"}])
nv3.load_volumes([{"path": DATA_FOLDER / "mni152.nii.gz"}])
## Create Interactive Controls
layout_dropdown = widgets.Dropdown(
options=[
("Auto", MultiplanarType.AUTO),
("Column", MultiplanarType.COLUMN),
("Grid", MultiplanarType.GRID),
("Row", MultiplanarType.ROW),
],
value=MultiplanarType.AUTO,
description="Layout:",
)
sync_dropdown = widgets.Dropdown(
options=[
("Sync Disabled", 0),
("Sync 2D", 1),
("Sync 3D", 2),
("Sync 2D and 3D", 3),
],
value=3,
description="Broadcast:",
)
status1 = widgets.HTML(value=" ")
status2 = widgets.HTML(value=" ")
status3 = widgets.HTML(value=" ")
## Setup Event Handlers
def on_layout_change(change):
"""Handle layout dropdown changes."""
new_layout = change["new"]
nv1.opts.multiplanar_layout = new_layout
nv2.opts.multiplanar_layout = new_layout
nv3.opts.multiplanar_layout = new_layout
def on_sync_change(change):
"""Handle sync mode dropdown changes."""
v = change["new"]
is_2d = False
is_3d = False
if v % 2: # If odd (1 or 3)
is_2d = True
if v > 1: # If 2 or 3
is_3d = True
nv1.broadcast_to([nv2, nv3], {"2d": is_2d, "3d": is_3d})
nv2.broadcast_to([nv1, nv3], {"2d": is_2d, "3d": is_3d})
nv3.broadcast_to([nv1, nv2], {"2d": is_2d, "3d": is_3d})
@nv1.on_location_change
def handle_location1(data):
"""Handle location string."""
status1.value = f" {data['string']}"
@nv2.on_location_change
def handle_location2(data):
"""Handle location string."""
status2.value = f" {data['string']}"
@nv3.on_location_change
def handle_location3(data):
"""Handle location string."""
status3.value = f" {data['string']}"
layout_dropdown.observe(on_layout_change, names="value")
sync_dropdown.observe(on_sync_change, names="value")
on_sync_change({"new": sync_dropdown.value})
## Display All
controls = widgets.HBox([layout_dropdown, sync_dropdown])
viewers = widgets.GridspecLayout(1, 3, height="400px")
viewers[0, 0] = nv1
viewers[0, 1] = nv2
viewers[0, 2] = nv3
status_row = widgets.HBox([status1, status2, status3])
display(widgets.VBox([controls, viewers, status_row]))